﻿using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Castle.Facilities.Logging;
using Abp.AspNetCore;
using Abp.AspNetCore.Mvc.Antiforgery;
using Abp.Castle.Logging.Log4Net;
using Abp.Extensions;
using pandx.Mulan.Configuration;
using pandx.Mulan.Identity;
using Abp.AspNetCore.SignalR.Hubs;
using Abp.Dependency;
using Abp.Json;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
using pandx.Mulan.Authentication.JwtBearer;
using pandx.Mulan.Swagger;

namespace pandx.Mulan.Web.Host.Startup
{
    public class Startup
    {
        private const string _defaultCorsPolicyName = "localhost";

        private const string _apiVersion = "v1";

        private readonly IConfigurationRoot _appConfiguration;
        private readonly IWebHostEnvironment _webHostEnvironment;

        public Startup(IWebHostEnvironment env)
        {
            _webHostEnvironment = env;
            _appConfiguration = env.GetAppConfiguration();
        }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            //MVC
            services.AddControllersWithViews(
                options => { options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute()); }
            ).AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance)
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                };
            });


            IdentityRegistrar.Register(services);
            AuthConfigurer.Configure(services, _appConfiguration);

            services.AddSignalR();

            // Configure CORS for angular2 UI
            services.AddCors(
                options => options.AddPolicy(
                    _defaultCorsPolicyName,
                    builder => builder
                        .WithOrigins(
                            // App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
                            _appConfiguration["App:CorsOrigins"]
                                .Split(",", StringSplitOptions.RemoveEmptyEntries)
                                .Select(o => o.RemovePostFix("/"))
                                .ToArray()
                        )
                        .SetIsOriginAllowedToAllowWildcardSubdomains()
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials()
                )
            );

            // Swagger - Enable this line and the related lines in Configure method to enable swagger UI
            // services.AddSwaggerGen(options =>
            // {
            //     options.SwaggerDoc(_apiVersion, new OpenApiInfo
            //     {
            //         Version = _apiVersion,
            //         Title = "Mulan API",
            //         Description = "Mulan",
            //         // uncomment if needed TermsOfService = new Uri("https://example.com/terms"),
            //         Contact = new OpenApiContact
            //         {
            //             Name = "Mulan",
            //             Email = string.Empty,
            //             Url = new Uri("https://twitter.com/aspboilerplate"),
            //         },
            //         License = new OpenApiLicense
            //         {
            //             Name = "MIT License",
            //             Url = new Uri("https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/LICENSE"),
            //         }
            //     });
            //     options.DocInclusionPredicate((docName, description) => true);
            //
            //     // Define the BearerAuth scheme that's in use
            //     options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
            //     {
            //         Description =
            //             "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
            //         Name = "Authorization",
            //         In = ParameterLocation.Header,
            //         Type = SecuritySchemeType.ApiKey
            //     });
            // });
            
            //Configure Swagger
            if (WebConsts.SwaggerUiEnabled)
            {
                services.AddSwaggerGen(options =>
                {
                    options.SwaggerDoc("v1", new OpenApiInfo() { Title = "Mulan API", Version = "v1" });
                    options.DocInclusionPredicate((docName, description) => true);
                    options.ParameterFilter<SwaggerEnumParameterFilter>();
                    options.SchemaFilter<SwaggerEnumSchemaFilter>();
                    options.OperationFilter<SwaggerOperationIdFilter>();
                    options.OperationFilter<SwaggerOperationFilter>();
                    options.CustomDefaultSchemaIdSelector();  
                    //add summaries to swagger
                    bool canShowSummaries = _appConfiguration.GetValue<bool>("Swagger:ShowSummaries");
                    if (canShowSummaries)
                    {
                        var hostXmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                        var hostXmlPath = Path.Combine(AppContext.BaseDirectory, hostXmlFile);
                        options.IncludeXmlComments(hostXmlPath);
                    
                        var applicationXml = $"MyCompanyName.AbpZeroTemplate.Application.xml";
                        var applicationXmlPath = Path.Combine(AppContext.BaseDirectory, applicationXml);
                        options.IncludeXmlComments(applicationXmlPath);
                    
                        var webCoreXmlFile = $"MyCompanyName.AbpZeroTemplate.Web.Core.xml";
                        var webCoreXmlPath = Path.Combine(AppContext.BaseDirectory, webCoreXmlFile);
                        options.IncludeXmlComments(webCoreXmlPath);
                    }
                });
            }

            // Configure Abp and Dependency Injection
            return services.AddAbp<MulanWebHostModule>(
                // Configure Log4Net logging
                options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                    f => f.UseAbpLog4Net().WithConfig("log4net.config")
                )
            );
        }

        public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
        {
            app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.
            
            app.UseStaticFiles();
            app.UseRouting();
            
            
            app.UseCors(_defaultCorsPolicyName); // Enable CORS!
            
            app.UseAuthentication();
            // app.UseJwtTokenMiddleware();
            // app.UseAbpRequestLocalization();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<AbpCommonHub>("/signalr");
                endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
            });

            if (WebConsts.SwaggerUiEnabled)
            {
                // // Enable middleware to serve generated Swagger as a JSON endpoint
                // app.UseSwagger(c => { c.RouteTemplate = "swagger/{documentName}/swagger.json"; });
                //
                // // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
                // app.UseSwaggerUI(options =>
                // {
                //     // specifying the Swagger JSON endpoint.
                //     options.SwaggerEndpoint($"/swagger/{_apiVersion}/swagger.json", $"Mulan API {_apiVersion}");
                //     options.IndexStream = () => Assembly.GetExecutingAssembly()
                //         .GetManifestResourceStream("pandx.Mulan.Web.Host.wwwroot.swagger.ui.index.html");
                //     options
                //         .DisplayRequestDuration(); // Controls the display of the request duration (in milliseconds) for "Try it out" requests.  
                // }); // URL: /swagger
                
                // Enable middleware to serve generated Swagger as a JSON endpoint
                app.UseSwagger();
                // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)

                app.UseSwaggerUI(options =>
                {
                    options.SwaggerEndpoint(_appConfiguration["App:SwaggerEndPoint"], "Mulan API V1");
                    options.IndexStream = () => Assembly.GetExecutingAssembly()
                        .GetManifestResourceStream("pandx.Mulan.Web.Host.wwwroot.swagger.ui.index.html");
                    options.InjectBaseUrl(_appConfiguration["App:ServerRootAddress"]);
                }); //URL: /swagger
            }
        }
    }
}